/**
 * 
 */
package com.wubo.sec.acl.core;

import java.util.Collection;

import org.aopalliance.intercept.MethodInvocation;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;

import com.wubo.sec.acl.annotation.Acl;
import com.wubo.spring.SpringApplicationContext;



/**
 * ACL投票人
 * @author WuBo
 * @CreateDate 2012-2-24
 */
public class AclVoter implements AccessDecisionVoter<Object> {
	private String prefix = "ACL_";
	
	private String supportClassName;

	public boolean supports(Class<?> clazz) {
		if(supportClassName != null){
			try{
				Class<?> supportClass = Class.forName(supportClassName);
				return supportClass.isAssignableFrom(clazz);
			}catch(Exception ignore){
				//do nothing
				System.err.println("ERROR: "+ignore.getMessage());
			}
		}
		return true;
	}

	public boolean supports(ConfigAttribute attribute) {
		if ((attribute.getAttribute() != null) && attribute.getAttribute().startsWith(getPrefix())) {
            return true;
        }
        else {
            return false;
        }
	}
	
	/**
	 * 当满足下列两个条件时，进行投票，否则弃权
	 * 1、此方法第二个参数object为MethodInvocation的实例（即在AOP中拦截方法）
	 * 2、被拦截方法的第一个参数为{@link#AclModel}的实例
	 */
	public int vote(Authentication authentication, Object object,
			Collection<ConfigAttribute> attributes) {
		int result = ACCESS_ABSTAIN;
        
		if(object instanceof MethodInvocation){
			MethodInvocation mi = (MethodInvocation) object;
			Object[] args = mi.getArguments();
			Object arg0 = null;
			if(args.length > 0){
				arg0 = args[0];
			}
			if(arg0 != null){
				GlobalAcl acl = null;
				if(arg0 instanceof AclModel) {
					AclModel aclModel = (AclModel) arg0;
					acl = aclModel.getAcl();
				}else{
					Acl aclAnno = arg0.getClass().getAnnotation(Acl.class);
					if(aclAnno != null){
						String name = aclAnno.name();
						String scope = aclAnno.scope();
						if("spring".equals(scope)){
							acl = (GlobalAcl) SpringApplicationContext.getBean(name);
						}
					}
				}

				String[] actions = null;
				if(acl == null){
					actions = AclManager.getInstance().getAction(0);
				}else{
					actions = AclManager.getInstance().getAction(acl.getAcl(arg0));
				}
				
		        for (ConfigAttribute attribute : attributes) {
		            if (this.supports(attribute)) {
		                result = ACCESS_DENIED;

		                for (String action : actions) {
		                    if (attribute.getAttribute().equals(action)) {
		                        return ACCESS_GRANTED;
		                    }
		                }
		            }
		        }
			}
	    	
		}
        return result;
	}

	public String getPrefix() {
		return prefix;
	}

	public void setPrefix(String prefix) {
		this.prefix = prefix;
	}

	public String getSupportClassName() {
		return supportClassName;
	}

	public void setSupportClassName(String supportClassName) {
		this.supportClassName = supportClassName;
	}

}
